using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using ApiDemo.Application.Common.Interface;
using ApiDemo.Application.Configuration;
using ApiDemo.Application.ReqDto;
using ApiDemo.Application.ResDto;
using ApiDemo.Domain.Entity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace ApiDemo.Infrastructure.Identity
{
    public class IdentityService : IIdentityService
    {
        private readonly IConfiguration _configuration;
        private readonly IRepository<AppUser> _appUserRepository;
        private readonly IIdentityUserService _appIdentityUserRepository;

        private AppUser? _appUser;

        public IdentityService(IConfiguration configuration, IRepository<AppUser> appUserRepository, IIdentityUserService appIdentityUserRepository)
        {
            _configuration = configuration;
            _appUserRepository = appUserRepository;
            _appIdentityUserRepository = appIdentityUserRepository;
        }
        public async Task<AppToken> GenerateToken()
        {
            var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
            var claims = new[]
           {
                new Claim("UserId",_appUser!.Id.ToString()),
                new Claim("Username",_appUser!.Username)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var securityToken = new JwtSecurityToken(jwtSetting.Issuer,jwtSetting.Audience,claims, expires: DateTime.UtcNow.AddMinutes(jwtSetting.AccessExpiration), signingCredentials: credentials);

            //生成token
            var token = new JwtSecurityTokenHandler().WriteToken(securityToken);
            var refreshToken = GenerateRefreshToken();

            var tmpIdentityUser = new AppIdentityUser
            {
                Username = _appUser.Username,
                RefreshToken = refreshToken,
                RefreshTokenExpiration = DateTime.UtcNow.AddMinutes(jwtSetting.RefreshExpiration)
            };
            await _appIdentityUserRepository.UpdateAsync(tmpIdentityUser);

            return new AppToken
            {
                AccessToken = token,
                RefreshToken = refreshToken
            };
        }

        public Task<AppToken> RefreshTokenAsync(AppToken appToken)
        {
            var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
            var au=new List<string>();
            au.Add(jwtSetting.Audience);
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,

                ValidIssuer = jwtSetting.Issuer,
                ValidAudience = jwtSetting.Audience,
                // ValidAudiences=au,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret))
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(appToken.AccessToken, tokenValidationParameters, out var securityToken);
            if (securityToken is not JwtSecurityToken jwtSecurityToken ||
                !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new SecurityTokenException("token无效");
            }

            var claimIdentity = principal.Identity as ClaimsIdentity;

            var username = claimIdentity!.FindFirst(x => x.Type == "Username")?.Value;

            var realName = username == null ? "" : username;

            var user = _appIdentityUserRepository.GetIdentityUserByUserNameAsync(realName);
            if (user == null || user.RefreshToken != appToken.RefreshToken || user.RefreshTokenExpiration <= DateTime.Now)
            {
                throw new Exception("传入的token或者refreshToken无效");
            }

            _appUser = _appUserRepository.Table.FirstOrDefault(x => x.Username == realName);
            return GenerateToken();
        }

        public bool ValidateUserAsync(UserForAuth userForAuth)
        {
            _appUser = _appUserRepository.Table.FirstOrDefault(x => x.Username == userForAuth.Username
             && x.Password == userForAuth.Password);

            return _appUser is null ? false : true;

        }

        private string GenerateRefreshToken()
        {
            // 创建一个随机的Token用做Refresh Token
            var rndNumber = new byte[32];

            using var rnd = RandomNumberGenerator.Create();
            rnd.GetBytes(rndNumber);

            return Convert.ToBase64String(rndNumber);
        }
    }
}